package utils;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.*;

/**
 * 
 * @Description   : pdf工具类
 * @Author        : huayixiu
 * @Creation Date : 2017年9月25日
 */
@SuppressWarnings("all")
public class PdfUtil {

    private static Logger logger = Logger.getLogger(PdfUtil.class);

    /**
     * 
     *  @Description    : 返回模板文件中要求的 filed name
     *  @Method_Name    : getContractTemplateFileFieldNames
     *  @param pdfFile
     *  @return
     *  @return         : Set<String>
     *  @Author         : huayixiu
     */
    public static Set<String> getContractTemplateFileFieldNames(File pdfFile) {
        return getContractTemplateFileFieldNames(pdfFile.getAbsolutePath());
    }

    /**
     * 
     *  @Description    : 返回模板文件中要求的 filed name
     *  @Method_Name    : getContractTemplateFileFieldNames
     *  @param pdfFileName
     *  @return
     *  @return         : Set<String>
     *  @Author         : huayixiu
     */
    public static Set<String> getContractTemplateFileFieldNames(String pdfFileName) {
        Set<String> fieldNames = new TreeSet<String>();
        PdfReader reader = null;
        try {
            reader = new PdfReader(pdfFileName);
            Set<String> keys = reader.getAcroFields().getFields().keySet();
            for (String key : keys) {
                int lastIndexOf = key.lastIndexOf(".");
                int lastIndexOf2 = key.lastIndexOf("[");
                fieldNames.add(key.substring(lastIndexOf != -1 ? lastIndexOf + 1 : 0, lastIndexOf2 != -1 ? lastIndexOf2 : key.length()));
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        } finally {
            if (reader != null) {
                reader.close();
            }
        }

        return fieldNames;
    }

    /**
     * 
     *  @Description    : 用模板和模板中field和field value 组成的Map对象 创建合同文件
     *  @Method_Name    : createContractFile
     *  @param fieldValueMap fieldName 和 fieldValue 的Map
     *  @param file 合同模板文件名(全路径名)
     *  @param contractFileName 所要创建的合同文件名(全路径名)
     *  @return         : void
     *  @Author         : huayixiu
     */
    public static void createContractFile(Map<String, String> fieldValueMap, byte[] file, String contractFileName) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(contractFileName);
            makePdf2OutputStream(fieldValueMap, file, fos);
        } catch (Exception e) {
            logger.error("生成协议文件异常", e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    //do nothing
                }
            }
        }
    }

    /**
     * 
     *  @Description    : 用模板和模板中field和field value 组成的Map对象 创建合同文件
     *  @Method_Name    : createContractFile
     *  @param fieldValueMap fieldName 和 fieldValue 的Map
     *  @param file 合同模板文件名(全路径名)
     *  @param contractFileName 所要创建的合同文件名(全路径名)
     *  @return         : void
     *  @Author         : huayixiu
     */
    private static void makePdf2OutputStream(Map<String, String> fieldValueMap, byte[] file, OutputStream os) {
        PdfReader reader = null;
        PdfStamper stamper = null;
        BaseFont base = null;

        try {
            reader = new PdfReader(file);
            stamper = new PdfStamper(reader, os);

            stamper.setFormFlattening(true);
            base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            AcroFields acroFields = stamper.getAcroFields();
            for (String key : acroFields.getFields().keySet()) {
                acroFields.setFieldProperty(key, "textfont", base, null);
                acroFields.setFieldProperty(key, "textsize", new Float(9), null);
            }

            if (fieldValueMap != null) {
                for (String fieldName : fieldValueMap.keySet()) {
                    acroFields.setField(fieldName, fieldValueMap.get(fieldName));
                }
            }
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage());
        } catch (DocumentException e) {
            logger.error(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage());
        } finally {
            if (stamper != null) {
                try {
                    stamper.close();
                } catch (DocumentException e) {
                    logger.error(e.getMessage());
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }

            if (reader != null) {
                reader.close();
            }
        }
    }

    /**
     * 
     *  @Description    : 读取文件数组
     *  @Method_Name    : fileBuff
     *  @param filePath
     *  @return
     *  @throws IOException
     *  @return         : byte[]
     *  @Author         : huayixiu
     */
    public static byte[] fileBuff(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            //System.out.println("file too big...");  
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] file_buff = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < file_buff.length && (numRead = fi.read(file_buff, offset, file_buff.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取  
        if (offset != file_buff.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }
        fi.close();
        return file_buff;
    }

    /**
     * 合并pdf 
     * @param files 源文件列表
     * @param savepath  保存文件路径
     */
    public static void mergePdfFiles(String[] files, String savepath) {
        Document document = null;
        try {
            document = new Document(); //默认A4大小
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
            document.open();
            for (int i = 0; i < files.length; i++) {
                PdfReader reader = null;
                try {
                    reader = new PdfReader(files[i]);
                    int n = reader.getNumberOfPages();
                    for (int j = 1; j <= n; j++) {
                        document.newPage();
                        PdfImportedPage page = copy.getImportedPage(reader, j);
                        copy.addPage(page);
                    }
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                }
            }
        } catch (Exception e) {
            logger.error("合并pdf失败", e);
        } finally {
            //关闭PDF文档流，OutputStream文件输出流也将在PDF文档流关闭方法内部关闭  
            if (document != null) {
                document.close();
            }

        }
    }

    /** 
     * pdf转图片
     * @param file pdf
     * @return  
     */
    public static byte[] pdf2Img(File file) {
        try {
            return pdfToPic(PDDocument.load(file));
        } catch (Exception e) {
            logger.error("pdf转图片异常：", e);
        }

        return null;
    }

    /**
     * pdf转图片
     */
    private static byte[] pdfToPic(PDDocument pdDocument) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        List<BufferedImage> piclist = new ArrayList<BufferedImage>();
        try {
            PDFRenderer renderer = new PDFRenderer(pdDocument);
            for (int i = 0; i < pdDocument.getNumberOfPages(); i++) {//
                // 0 表示第一页，300 表示转换 dpi，越大转换后越清晰，相对转换速度越慢
                BufferedImage image = renderer.renderImageWithDPI(i, 108);
                piclist.add(image);
            }
            // 总高度 总宽度 临时的高度 , 或保存偏移高度 临时的高度，主要保存每个高度
            int height = 0, width = 0, _height = 0, __height = 0,
                    // 图片的数量
                    picNum = piclist.size();
            // 保存每个文件的高度
            int[] heightArray = new int[picNum];
            // 保存图片流
            BufferedImage buffer = null;
            // 保存所有的图片的RGB
            List<int[]> imgRGB = new ArrayList<int[]>();
            // 保存一张图片中的RGB数据
            int[] _imgRGB;
            for (int i = 0; i < picNum; i++) {
                buffer = piclist.get(i);
                heightArray[i] = _height = buffer.getHeight();// 图片高度
                if (i == 0) {
                    // 图片宽度
                    width = buffer.getWidth();
                }
                // 获取总高度
                height += _height;
                // 从图片中读取RGB
                _imgRGB = new int[width * _height];
                _imgRGB = buffer.getRGB(0, 0, width, _height, _imgRGB, 0, width);
                imgRGB.add(_imgRGB);
            }

            // 设置偏移高度为0
            _height = 0;
            // 生成新图片
            BufferedImage imageResult = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            int[] lineRGB = new int[8 * width];
            int c = new Color(128, 128, 128).getRGB();
            for (int i = 0; i < lineRGB.length; i++) {
                lineRGB[i] = c;
            }
            for (int i = 0; i < picNum; i++) {
                __height = heightArray[i];
                // 计算偏移高度
                if (i != 0)
                    _height += __height;
                imageResult.setRGB(0, _height, width, __height, imgRGB.get(i), 0, width); // 写入流中

                // 模拟页分隔
                if (i > 0) {
                    imageResult.setRGB(0, _height + 2, width, 8, lineRGB, 0, width);
                }
            }
            // 写流
            ImageIO.write(imageResult, "jpg", baos);
        } catch (Exception e) {
            logger.error("pdf转图片异常：", e);
        } finally {
            IOUtils.closeQuietly(baos);
            try {
                pdDocument.close();
            } catch (Exception ignore) {
            }
        }

        return baos.toByteArray();
    }

    public static void main(String[] args) {
        HashMap map = new HashMap<String, String>();

        createContractFile(map, null, null);
    }
}
